package com.midipad;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.UUID;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.DialogInterface.OnClickListener;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.text.util.Linkify;
import android.util.Log;
import android.view.Display;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.WindowManager;
import android.widget.TextView;
import android.widget.Toast;
import backport.android.bluetooth.BluetoothAdapter;
import backport.android.bluetooth.BluetoothDevice;
import backport.android.bluetooth.BluetoothSocket;

import com.midipad.controls.MidiController;
import com.midipad.layout.ControllersLayout;

/**
 * The main activity,
 * consist mainly into bluetooth handling so should be revised
 * drastically when the 2.0 updated api will be out
 * @author Tim
 *
 */
public class MidiPad extends Activity{
	
	//the bluetooth server port to connect to
	protected int serverPort;
	
	//log tag
	public static final String TAG = "MidiPad";
	
	//request codes for activities with result
	protected static final int REQUEST_CONFIG = 10;
	protected static final int REQUEST_OPEN_FILE = 20;
	
	//the list of midi controllers
	protected ArrayList<MidiController> controllers = null;
	//custom layout for absolute positionning
	protected ControllersLayout layout = null;
	
	//bluetooth
	protected BluetoothDevice rbd = null;
	protected BluetoothSocket socketBt = null;
	protected OutputStreamWriter osw = null;
	protected InputStreamReader isr = null;
	BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
	protected final static UUID uuid = UUID.fromString("ce0ab4c0-0986-11df-8a39-0800200c9a66");
	protected static final int REQUEST_ENABLE_BT = 30;
	protected static final int REQUEST_SELECT_DEVICE = 40;
	protected ConnectedThread connectedThread= null;
	
	//preferences
	protected boolean allowMidiInput;
	protected boolean allowMidiOutput;
	
	//telephony manager
	protected TelephonyManager telMgr = null;
	
	/** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        controllers = new ArrayList<MidiController>();
        layout = new ControllersLayout(this, controllers);
        
        TextView textWelcome = new TextView(this);
        textWelcome.setAutoLinkMask(Linkify.WEB_URLS);
        textWelcome.setText(getResources().getString(R.string.welcome));
    	setContentView(textWelcome);
        
    	telMgr = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
    	telMgr.listen(new PhoneStateListener(){
    		@Override
    		public void onCallStateChanged(int state, String incomingNumber){
    			switch(state){
    			case TelephonyManager.CALL_STATE_RINGING:
    				//TODO:
    				break;
    			}
    		}
    	}, PhoneStateListener.LISTEN_CALL_STATE);
    	//debug times
        //loadInterface("/sdcard/ableton5x5.xml");
        //setContentView(layout);
    	
    	if (mBluetoothAdapter == null) {
    	    // Device does not support Bluetooth
    		new AlertDialog.Builder(this)
    		.setMessage("Your device is not bluetooth enabled.")
    		.setTitle("Sorry")
    		.setCancelable(false)
    		.setPositiveButton("Exit", new OnClickListener() {
				public void onClick(DialogInterface arg0, int arg1) {
					arg0.dismiss();
					finish();
				}
			}).show();
    	}
    	
    	//settings
    	SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
    	allowMidiInput = prefs.getBoolean("allow_midi_input", true);
    	allowMidiOutput = prefs.getBoolean("allow_midi_output", true);
    }
	
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
	    MenuInflater inflater = getMenuInflater();
	    inflater.inflate(R.menu.optionmenu, menu);
	    return true;
	}
	
	/**
	 * closes everything that needs to be closed
	 */
	protected void disconnectBt(){
		if(socketBt!=null){
			try {
				socketBt.close();
				socketBt=null;
			} catch (IOException e) {
				e.printStackTrace();
			}
			//osw.close();
			//isr.close();
		}
	}
	
	protected void onResume() 
    {
        super.onResume();
    }
	
	
	/**
	 * launch the discovery of bluetooth devices, or enable bluetooth if not enabled
	 */
	protected void connectBt(){
		try {
			if (!mBluetoothAdapter.isEnabled()) {
				Log.d(TAG, "Enabling Bluetooth");
			    Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
			    startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
			}else{
				Intent i = new Intent(this, DiscoveryActivity.class);
				startActivityForResult(i, REQUEST_SELECT_DEVICE);
			}
		} catch (Exception e) {
			e.printStackTrace();
			Toast.makeText(this, "Could not initialize bluetooth device",Toast.LENGTH_SHORT);
		}
	}
	
	protected void makeDiscoverable(){
		Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
		discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
		startActivity(discoverableIntent);
	}
	
	@Override
	protected void onDestroy(){
		super.onDestroy();
		disconnectBt();
	}
	
	/**
	 * Handles option item selections  
	 */
	public boolean onOptionsItemSelected(MenuItem item) {
	    switch (item.getItemId()) {
	    case R.id.itemBtConnect:
	    	connectBt();
	    	return true;
	    case R.id.itemAbout:
	    	new AlertDialog.Builder(this).setTitle("About this application")
	    	.setIcon(R.drawable.icon)
	    	.setPositiveButton("Back", null)
	    	.setMessage(getResources().getString(R.string.about_content))
	    	.show();
	    	return true;
	    case R.id.itemOpen:
	    	Intent intent = new Intent(MidiPad.this, FileBrowser.class);
	    	startActivityForResult(intent, REQUEST_OPEN_FILE);
	    	return true;
	    case R.id.preferences:
	    	intent = new Intent(MidiPad.this, Prefs.class);
	    	startActivityForResult(intent, REQUEST_CONFIG);
	    }
	    return false;
	}
	
	/**
	 * handles launched activities results
	 */
	protected void onActivityResult(int requestCode, int resultCode, Intent intent){
		Log.i("","an activity has finished");
		// See which child activity is calling us back.
	    switch (requestCode) {
	        case REQUEST_OPEN_FILE:
	        	if (resultCode == RESULT_CANCELED){
	                Log.d("","Canceled opening an interface");
	            } else if(resultCode== RESULT_OK){
	        		Log.d("","Selected a file");
	        		Bundle extras = intent.getExtras();
	        		String filePath = extras.getString("FILE_PATH");
	        		loadInterface(filePath);
	            }
	        	break;
	        case REQUEST_ENABLE_BT:
	        	if (resultCode == RESULT_OK){
	        		Log.d(TAG, "Bluetooth has been enabled");
	        		Toast.makeText(this, "Bluetooth has been enabled", Toast.LENGTH_SHORT).show();
	        	}
	        	break;
	        case REQUEST_SELECT_DEVICE:
	        	if(resultCode == RESULT_OK){
	        		String mac = intent.getExtras().getString(DiscoveryActivity.EXTRA_DEVICE_ADDRESS); 
	        		Log.d(TAG, "A device has been selected : "+mac);
	        		rbd  = mBluetoothAdapter.getRemoteDevice(mac);
	        		try {
						socketBt = rbd.createRfcommSocketToServiceRecord(uuid);
						socketBt.connect();
						connectedThread = new ConnectedThread(socketBt, this.mHandler);
						connectedThread.start();
						
						//TODO:why the expception is not caught??
	        		} catch (IOException e) {
	        			new AlertDialog.Builder(this)
	        			.setTitle("Bluetooth error")
	        			.setMessage("Sorry, could not connect to the specified device")
	        			.setPositiveButton("Close", new OnClickListener() {
							public void onClick(DialogInterface arg0, int arg1) {
								arg0.dismiss();
							}
						}).show();
	        			break;
	        		}
	        		assignThreadToControllers();
					Log.d("R BL", "Assigned the socket handler to all the controllers");
	        	}
	        case REQUEST_CONFIG:
	        	SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
	        	allowMidiInput = prefs.getBoolean("allow_midi_input", true);
	        	allowMidiOutput = prefs.getBoolean("allow_midi_output", true);
	        	//TODO:where to handle ongoing io?
	        	break;
	        default:
	            break;
	    }
	}
       
    
    protected void assignThreadToControllers(){
    	for(int i=0 ; i<controllers.size() ; i++){
			controllers.get(i).setConnectedThread(connectedThread);
		}
    }
    
    /**
     * loads an xml interface
     * @param filePath the absolute path to the file to load
     */
    protected void loadInterface(String filePath){
    	layout.removeAllViews();
    	controllers.clear();
    	WindowManager w = getWindowManager();
        Display d = w.getDefaultDisplay();
    	Log.d(TAG, "width, height of screen :"+d.getWidth()+","+d.getHeight());
    	DomInterfaceReader.parse(filePath, this, controllers, layout, d.getWidth(), d.getHeight());
    	setContentView(layout);
    	layout.requestLayout();
    	assignThreadToControllers();
    }
    
    
    public final static int MESSAGE_READ = 1;
    //public final static int MESSAGE_WRITE = 2;
    protected Handler mHandler = new Handler(){
    	@Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
//            case MESSAGE_WRITE:
//                byte[] writeBuf = (byte[]) msg.obj;
//                // construct a string from the buffer
//                String writeMessage = new String(writeBuf);
//                Log.d(TAG, "sent to bt:"+writeMessage);
//                break;
            case MESSAGE_READ:
                byte[] readBuf = (byte[]) msg.obj;
                // construct a string from the valid bytes in the buffer
                String readMessage = new String(readBuf, 0, msg.arg1);
                Log.d(TAG, "received from bt:"+readMessage);
                //find the controller which is connected to it:
                int val1 = readBuf[0];
                int val2 = readBuf[1];
                int val3 = readBuf[2];
                MidiController controller = null;
                int i=0;
                int nbControllers = controllers.size();
                for(i=0 ; i<nbControllers ; i++){
                	controller = controllers.get(i);
                	if(controller.concernsMe(val1, val2)){
                		controller.setValues(val1, val2, val3);
                		controller.invalidate();
                		break;
                	}
                }
                break;
        }
    }};
}

